structure Main  =
struct

structure Ast = Ast (open Atoms)
                
structure Types2 = Types2 (open Atoms)
                   
structure TyTable = Table (open Atoms
structure Types = Types2)
                    
structure Intp = Interp (structure Ast = Ast)
                 
structure Ir = Ir (open Atoms
structure Types = Types2)
               
structure E = ErrorMsg
structure E2 = AsmErrorMsg
               
structure Parse = Parse (structure Ast = Ast)
                  
structure T = TypeCheckMain (structure Table = TyTable
structure Ast = Ast
structure Ir = Ir
structure Types2 = Types2) 
              
structure IrMain = IrMain (structure Ir = Ir)
                   
                   
structure Cfg = Cfg (open Atoms
structure Types = Types2)
                
structure CfgMain = CfgMain (structure Ir = Ir
structure Cfg = Cfg)
                    
structure Machine = Machine (open Atoms
structure Types = Types2)   
                    
structure MachineMain = MachineMain (structure Machine = Machine
structure Cfg = Cfg)
                        
structure X86Asm = X86Asm (open Atoms
structure Types = Types2)   
                   
structure X86AsmMain = X86AsmMain (structure Machine = Machine
structure X86Asm = X86Asm)
                       
exception ParseFailed
exception TypeCheckFailed
exception OptAstFailed
exception Ast2IrFailed
exception SrcPtrLogicFailed
exception EmitAssemFailed
exception AsmPtrLogicFailed
exception EmitProofFailed
exception ExeFailed
exception Success
exception Failed
          
exception CompilationFail
          
structure FileKind =
struct
 
fun check file =
    case List.rev (String.explode file)
     of (#"c") :: (#".") :: _ => ()
      | (#"C") :: (#".") :: _ => ()
      | _ => Control.error "bad file suffix, .c or .C wanted"
end
          
fun main file =
    let val _ = ((*init (); *)E.reset();
                              E2.reset();
                              Temp.reset();
                              E.file := file;
                              E2.file := file(*;
                                                  Compiler.Control.Print.printDepth := 100;
                                              Compiler.Control.Print.printLength := 100*))
        fun say s =
            if (!Control.doShowPass)
            then print s
            else ()
        val strFileName = File.nameToString file
        val _ = FileKind.check strFileName
    in  let val _ = say (String.concat ["compile: ",
                                                 strFileName,
                                                 " starting\n\n"])
            val _ = say "lexing and parsing starting\n"
            val ast = Parse.parse strFileName
            val _ = if (!E.anyErrors)
                    then raise Failed
                    else ()
            val _ = say "lexing and parsing finished\n\n"
            val _ = if !Control.doKeepAst
                    then File.output (strFileName^".ast.c", Ast.Program.toString ast)
                    else ()
                         
            val _ = say "type check and translate to ir starting\n"
            val ir = T.typeCkProg ast
            val _ = if (!E.anyErrors)
                    then raise Failed
                    else ()
            val _ = say "type check and translate to ir finished\n\n"
            val _ = if !Control.doKeepIr
                    then File.output (strFileName^".ir.c", Ir.Program.toString ir)
                    else ()
                         
            val _ = say "optimize ir starting\n"
            val ir = IrMain.shrink ir
            val _ = if (!E.anyErrors)
                    then raise Failed
                    else ()
            val _ = say "optimize ir finished\n\n"
                    
            val _ = say "translate to CFG starting\n"
            val cfg = CfgMain.ir2cfg ir              
            val _ = if (!E.anyErrors)
                    then raise Failed
                    else ()
            val _ = say "translate to CFG finished\n\n"              
            
            val _ = say "translate to Machine starting\n"
            val machine = MachineMain.trans cfg              
            val _ = if (!E.anyErrors) then raise Failed else ()
            val _ = say "translate to Machine finished\n\n"              
            val _ = if !Control.doKeepMachine
                    then File.output (strFileName^".rtl.c", Machine.Program.toString machine)
                    else ()
                         
            val _ = say "translate to x86 assembly starting\n"
            val asm = X86AsmMain.trans machine              
            val _ = if (!E.anyErrors) then raise Failed else ()
            val _ = say "translate to x86 assembly finished\n\n"
            val _ = if !Control.doKeepAsm
                    then File.output (strFileName^".asm.c", X86Asm.Program.toString asm)
                    else ()
                         
            val _ = if (!Control.doKeepAssembly)
		    then ()
		    else let val _ = say "produce executables starting\n"
                         (*                fun try () = TextIO.closeOut (TextIO.openOut "lib/tcclib.o")
                                               handle Io => (print "invalid library path : lib/tcclib.o\n"
                                                           ; raise Failed)
                                           val _ = try ()
                                           val cmd1 = String.concat ["gcc ", 
                                                                     "lib/tcclib.c ",
                                                                     strFileName,
                                                                     ".s ",
                                                                     " -o ",
                                                                     !Control.fileName]
                                           val cmd2 = String.concat ["gcc ",
                                                                     "lib/tcclib.c ",
                                                                     strFileName,
                                                                     ".s ",
                                                                     "-o ",
                                                                     strFileName,
                                                                     ".exe"]                               
			                   val _ = if (!Control.doSetFileName)
        			                   then OS.Process.system cmd1
				                   else OS.Process.system cmd2
			                   val _ = if (!E.anyErrors) then raise  Failed else ()
			                   val _ = say "produce executables finished\n\n"
			  *)
			 in  ()
			 end
                         
            val _ = if (!Control.doKeepAssembly)
                    then ()
                    else ignore (OS.Process.system (String.concat ["rm ", File.nameToString file, ".s"]))
                         
            val _ = say (String.concat ["compile: ", File.nameToString file, " finished\n"])
        in  ()
        end
        
val top = fn x => main (File.creat x) handle _ => ()
    end
    
